#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <unistd.h>
#define MAX_RETRIES 10

union semun
{
  int val;
  struct semid_ds *buf;
  ushort *array;
};

/*
** initsem() -- more-than-inspired by W. Richard Stevens' UNIX Network
** Programming 2nd edition, volume 2, lockvsem.c, page 295.
*/
int
initSem (key_t key, int nsems)	/* key from ftok() */
{
  int i;
  union semun arg;
  struct semid_ds buf;
  struct sembuf sb;
  int semid;
/*get a set of semaphore*/
  semid = semget (key, nsems, IPC_CREAT | IPC_EXCL | 0600);

  if (semid >= 0)
    {				/* we got it first */
      sb.sem_op = 1;
      sb.sem_flg = SEM_UNDO;
      arg.val = 1;


      for (sb.sem_num = 0; sb.sem_num < nsems; sb.sem_num++)
	{
		/*Initilizision*/
	  /* do a semop() to "free" the semaphores. */
	  /* this sets the sem_otime field, as needed below. */
	  if (semop (semid, &sb, 1) == -1)
	    {
	      int e = errno;
	      semctl (semid, 0, IPC_RMID);	/* clean up */
	      errno = e;
	      return -1;	/* error, check errno */
	    }
	}

    }
  else if (errno == EEXIST)
    {				/* someone else got it first */
      int ready = 0;

      semid = semget (key, nsems, 0);	/* get the id */
      if (semid < 0)
	return semid;		/* error, check errno */

      /* wait for other process to initialize the semaphore: */
      arg.buf = &buf;
      for (i = 0; i < MAX_RETRIES && !ready; i++)
	{
	  semctl (semid, nsems - 1, IPC_STAT, arg);
	  if (arg.buf->sem_otime != 0)
	    {
	      ready = 1;
	    }
	  else
	    {
	      sleep (1);
	    }
	}
      if (!ready)
	{
	  errno = ETIME;
	  return -1;
	}
    }
  else
    {
      return semid;		/* error, check errno */
    }

  return semid;
}
int
lockSem(int semid)
{
	struct sembuf sb;
    sb.sem_num = 0;
    sb.sem_op = -1;  /* set to allocate resource */
    sb.sem_flg = SEM_UNDO;
    return semop(semid, &sb, 1);
}
int lockSemTime(int semid,struct timespec tm)
{
	struct sembuf sb;
    sb.sem_num = 0;
    sb.sem_op = -1;  /* set to allocate resource */
    sb.sem_flg = SEM_UNDO;
    return semop(semid, &sb, 1);	
}
int
freeSem(int semid)
{
	struct sembuf sb;
    sb.sem_num = 0;
    sb.sem_flg = IPC_NOWAIT;
    sb.sem_op = 1; /* free resource */
    return semop(semid, &sb, 1);
}
void
removeSem(int semid)
{
	if (-1 == semctl (semid, 0, IPC_RMID))
    {
      perror ("semctl");
    }
}
